from Quartz import *
#from sagePointer import onPtrCaptured, onPtrReleased, stopGUI
import wx, time
import traceback as tb
from math import floor, ceil
from managerConn import ManagerConnection

global firstMsg, runLoopSource, manager, config
global onPtrCaptured, onPtrReleased, stopGUI

MOVE = 1
CLICK = 2
WHEEL = 3
COLOR = 4

LEFT=1
RIGHT=2
MIDDLE = 3  


# get display height
dispSize = CGDisplayBounds(CGMainDisplayID())
width = dispSize.size.width
height = dispSize.size.height
captured = False
quitRunLoop = False

lastTime = time.time()
firstMsg = True



def setConnectionManager(man):
    global manager
    manager.disconnect()
    manager.quit()
    manager = man


def stopCaptureThread():
    global quitRunLoop
    quitRunLoop = True
    manager.quit()
    config.save()


def sendMsg(*data):
    global firstMsg, captured

    msg = ""
    for m in data:
        msg+=str(m)+" "
    manager.sendMessage(config.ptrLabel, "mouse", msg)

    if captured and firstMsg:
        time.sleep(0.5)
        firstMsg = False
        manager.sendMessage(config.ptrLabel, "mouse", str(COLOR) + " " + 
                            str(config.ptrColor.Red()) + " " +
                            str(config.ptrColor.Green()) + " " +
                            str(config.ptrColor.Blue()))


def stopRunLoop():
    print "\nSAGEPointer: stopping run loop"
    CFRunLoopRemoveSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes)
    CFRunLoopStop(CFRunLoopGetCurrent())


def myCGEventCallback(proxy, eventType, event, h):
    global captured, firstMsg
 
    try:    
        if quitRunLoop:
            stopRunLoop()
            return None

        retVal = event

        location = CGEventGetLocation(event)
        if eventType == kCGEventMouseMoved or eventType == kCGEventLeftMouseDragged or eventType == kCGEventRightMouseDragged:
            mx,my = location.x, location.y
            x = float(mx/float(width))
            y = 1-float(my/float(height))
            if captured:
                global lastTime
                if time.time() - lastTime >= 1/50.0:
                    lastTime = time.time()
                    sendMsg(MOVE, x, y)
                retVal = None

        elif eventType == kCGEventLeftMouseDown:
            if captured: 
                sendMsg(CLICK, LEFT, 1)
                retVal = None

        elif eventType == kCGEventLeftMouseUp:
            if captured: 
                sendMsg(CLICK, LEFT, 0)
                retVal = None

        elif eventType == kCGEventRightMouseDown:
            if captured: 
                sendMsg(CLICK, RIGHT, 1)
                retVal = None
                
        elif eventType == kCGEventRightMouseUp:
            if captured: 
                sendMsg(CLICK, RIGHT, 0)
                retVal = None

        elif eventType == kCGEventScrollWheel:
            numSteps = CGEventGetIntegerValueField(event, kCGScrollWheelEventPointDeltaAxis1)
            if captured: 
                if numSteps > 0: cap = ceil
                else: cap = floor
                sendMsg(WHEEL, -1*int(cap((numSteps)/2.0)))
                retVal = None

        elif eventType == kCGEventKeyDown:
            keycode = CGEventGetIntegerValueField(event, kCGKeyboardEventKeycode)
            if (( (CGEventGetFlags(event) & kCGEventFlagMaskAlphaShift==kCGEventFlagMaskAlphaShift) or captured) and keycode==48) or \
                    (keycode == 113 or keycode == 105 or keycode == 107):
                if captured: 
                    captured = False
                    manager.disconnect()
                    onPtrReleased() 
                else:
                    onPtrCaptured()
                    firstMsg = True
                    captured = True
                retVal = None
               
    except: 
        print "\nSAGEPointer: EXCEPTION during event processing..."
        tb.print_exc()
        manager.quit()
        stopGUI()
        stopRunLoop()
      
    return retVal



def captureThread(conf, cap, rel, stop):
    global runLoopSource, config, manager
    global onPtrCaptured, onPtrReleased, stopGUI
    onPtrCaptured = cap
    onPtrReleased = rel
    stopGUI = stop
    config = conf
    manager = ManagerConnection(config.sageHost, 20005)

    try:
        # we want these events
        eventMask = ((1 << kCGEventMouseMoved) | 
                     (1 << kCGEventLeftMouseDown) | 
                     (1 << kCGEventLeftMouseUp) |
                     (1 << kCGEventLeftMouseDragged) |
                     (1 << kCGEventRightMouseDown) | 
                     (1 << kCGEventRightMouseUp) |
                     (1 << kCGEventRightMouseDragged) |
                     (1 << kCGEventScrollWheel) |
                     (1 << kCGEventKeyDown) |
                     (1 << kCGEventKeyUp))

        # create a callback
        eventTap = CGEventTapCreate(kCGSessionEventTap, kCGHeadInsertEventTap, 0, \
                                        eventMask, myCGEventCallback, "hello")
        # Create a run loop source.
        runLoopSource = CFMachPortCreateRunLoopSource(kCFAllocatorDefault, eventTap, 0)

        # Add to the current run loop.
        CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopCommonModes)

        # Enable the event tap.
        CGEventTapEnable(eventTap, True)

        # Set it all running.
        CFRunLoopRun()
        print "\nSAGEPointer: Run Loop ended..."

    except KeyboardInterrupt:
        print "\nSAGEPointer: Keyboard interrupt"
        manager.quit()
        stopGUI()
   
    except:
        print "\nSAGEPointer: EXCEPTION:"
        tb.print_exc()

    print "\nSAGEPointer: Capture Thread ended..."
